package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.lang.tree.parser.NodeParser;
import com.zzyl.constant.CacheConstant;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * @Description ResourceServiceImpl
 * @Author loe
 * @Date 2024-07-14
 */

@Service
public class ResourceServiceImpl implements ResourceService {

    @Autowired
    private ResourceMapper resourceMapper;

    /**
     * 资源列表查询
     *
     * @param resourceDto
     * @return
     */
    @Cacheable(value = CacheConstant.RESOURCE_LIST, key = "#resourceDto.hashCode()")
    @Override
    public List<ResourceVo> getResourceList(ResourceDto resourceDto) {
        List<Resource> resourceList = resourceMapper.getResourceList(resourceDto);
        return BeanUtil.copyToList(resourceList, ResourceVo.class);
    }

    /**
     * 资源修改
     *
     * @param resourceDto
     */
    @Caching(
            evict = {
                    @CacheEvict(value = CacheConstant.RESOURCE_LIST, allEntries = true),
                    @CacheEvict(value = CacheConstant.RESOURCE_TREE, allEntries = true)
            }
    )
    @Override
    public void updateResource(ResourceDto resourceDto) {
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        resourceMapper.updateByPrimaryKeySelective(resource);
    }

    /**
     * 启用禁用
     *
     * @param resourceDto
     */
    @Caching(
            evict = {
                    @CacheEvict(value = CacheConstant.RESOURCE_LIST, allEntries = true),
                    @CacheEvict(value = CacheConstant.RESOURCE_TREE, allEntries = true)
            }
    )
    @Override
    public void setDataStatus(ResourceDto resourceDto) {
        int parentState = resourceMapper.getParentStatus(resourceDto.getParentResourceNo());
        if (parentState == 1) {
            throw new BaseException(BasicEnum.PARENT_MENU_DISABLE);
        }
        char dataState = resourceDto.getDataState().charAt(0);
        String processedNo = NoProcessing.processString(resourceDto.getResourceNo());
        resourceMapper.updateStatus(dataState, processedNo);
    }

    /**
     * 资源树形
     *
     * @param resourceDto
     * @return
     */
    @Cacheable(value = CacheConstant.RESOURCE_TREE, key = "#resourceDto.hashCode()", unless = "#result == null")
    @Override
    public TreeVo resourceTree(ResourceDto resourceDto) {
        // 1.构建查询条件
        ResourceDto dto = ResourceDto.builder().dataState(SuperConstant.DATA_STATE_0)
                .parentResourceNo(NoProcessing.processString(SuperConstant.ROOT_PARENT_ID))
                .resourceType(SuperConstant.MENU)
                .build();

        // 2.查询所有资源数据
        List<Resource> resourceList = resourceMapper.getResourceList(dto);

        List<TreeItemVo> itemVoList = new ArrayList<>();

        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setNameKey("label");
        List<Tree<String>> treeList = TreeUtil.build(resourceList, SuperConstant.ROOT_PARENT_ID, treeNodeConfig, new NodeParser<Resource, String>() {
            @Override
            public void parse(Resource resource, Tree<String> treeNode) {
                treeNode.setId(resource.getResourceNo());
                treeNode.setParentId(resource.getParentResourceNo());
                treeNode.setName(resource.getResourceName());
            }
        });

        List<TreeItemVo> treeItemVos = BeanUtil.copyToList(treeList, TreeItemVo.class);

        TreeItemVo items = TreeItemVo.builder().id(SuperConstant.ROOT_PARENT_ID).label("智慧养老院").children(treeItemVos).build();

        return new TreeVo(List.of(items));
    }

    /**
     * 资源新增
     *
     * @param resourceDto
     */
    @Caching(
            evict = {
                    @CacheEvict(value = CacheConstant.RESOURCE_LIST, allEntries = true),
                    @CacheEvict(value = CacheConstant.RESOURCE_TREE, allEntries = true)
            }
    )
    @Override
    public void insertResource(ResourceDto resourceDto) {
        // 1.将dto转成实体类
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);

        // 2.与父节点状态保持一致
        Resource parentResource = resourceMapper.getResourceByNo(resource.getParentResourceNo());
        resource.setDataState(parentResource.getDataState());

        // 3.添加子资源编号
        createResourceNo(resource);

        // 4.插入
        resourceMapper.insertSelective(resource);
    }

    private void createResourceNo(Resource resource) {
        // 如果是菜单并且是三级菜单直接抛异常
        if (resource.getResourceType().equals(SuperConstant.MENU)
                && NoProcessing.processString(resource.getParentResourceNo()).length() / 3 > 4) {
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }
        // 不大于三级, 查询该父资源是否有子节点
        ResourceDto dto = ResourceDto.builder().parentResourceNo(resource.getParentResourceNo()).build();
        List<Resource> resourceList = resourceMapper.getResourceList(dto);

        if (resourceList.isEmpty()) {
            // 父节点没有下属节点
            resource.setResourceNo(NoProcessing.createNo(resource.getParentResourceNo(), false));
        } else {
            // 父节点有下属节点, 找到最大的节点
            Long max = 0L;
            for (Resource r : resourceList) {
                Long l = Long.valueOf(r.getResourceNo());
                max = max > l ? max : l;
            }
            resource.setResourceNo(NoProcessing.createNo(max.toString(), true));
        }
    }

    /**
     * 菜单删除
     *
     * @param menuId
     */
    @Caching(
            evict = {
                    @CacheEvict(value = CacheConstant.RESOURCE_LIST, allEntries = true),
                    @CacheEvict(value = CacheConstant.RESOURCE_TREE, allEntries = true)
            }
    )
    @Override
    @Transactional
    public void deleteById(String menuId) {
        String processed = NoProcessing.processString(menuId);

        // 判断是否有除本身外的子菜单
        int i = resourceMapper.IsChildren(processed);
        if (i > 1) {
            throw new BaseException(BasicEnum.MENU_HAVE_CHILDREN);
        }

        // 判断是否绑定角色
        int j = resourceMapper.IsRole(menuId);
        if (j == 1) {
            throw new BaseException(BasicEnum.MENU_BOUND_ROLE);
        } else {
            resourceMapper.deleteByResourceNo(menuId);
        }
    }

    /**
     * 动态菜单
     * @return
     */
    @Override
    public List<MenuVo> getMotionMenu() {
        // 1.查询所有的数据
        Long userId = UserThreadLocal.getMgtUserId();
        List<MenuVo> menuVoList = resourceMapper.getUserResource(userId);
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setIdKey("resourceNo");
        treeNodeConfig.setParentIdKey("parentResourceNo");
        List<Tree<String>> treeList = TreeUtil.build(menuVoList, SuperConstant.ROOT_PARENT_ID, treeNodeConfig, (menuVo, treeNode) -> {
            treeNode.setId(menuVo.getResourceNo());
            treeNode.setParentId(menuVo.getParentResourceNo());
            treeNode.setName(menuVo.getName());
            treeNode.putExtra("path", menuVo.getPath());
            treeNode.putExtra("redirect", "/" + menuVo.getName());
            treeNode.putExtra("meta", menuVo.getMeta());
        });
        return BeanUtil.copyToList(treeList, MenuVo.class);
    }
}
